/**
 * 溶洞土压力计算相关算法实现
 * 提供溶洞工程中各种土压力和应力系数的计算函数
 * 适用于隧道工程中溶洞处理的相关计算场景
 * 
 * 该类包含了溶洞土压力计算的核心算法实现，基于太沙基理论、朗肯土压力理论等经典土力学理论
 * 所有方法均为静态方法，可以直接通过类名调用
 */
export class CaveAlgorithms {

  /**
   * 溶洞土压力计算
   * 基于太沙基理论计算溶洞顶部的土压力值
   * 
   * @param gamma_f 溶洞充填物重度(kN/m³)，单位体积物质的重量
   * @param S 溶洞充填物围岩级别，范围通常为1-6级
   * @param i 围岩压力增减率，根据实际工程情况调整的系数
   * @param B_f 溶洞宽度(m)，溶洞的水平方向最大尺寸
   * @returns {number} q - 作用在溶洞顶部的土压力值(kPa)
   * @returns {number} h_q - 土柱换算高度(m)，等效作用高度
   */
  static caveSoilPressure(gamma_f: number, S: number, i: number, B_f: number): { q: number, h_q: number } {
    // 计算土柱换算高度 h_q = 0.45 × 2^(S-1) × (1 + i × (B_f - 5))
    // 其中 0.45 为基础系数，2^(S-1) 为围岩级别影响系数，(1 + i × (B_f - 5)) 为宽度修正系数
    const h_q = 0.45 * Math.pow(2, S - 1) * (1 + i * (B_f - 5));
    
    // 计算土压力 q = γ_f × h_q，其中 γ_f 为土体重度
    const q = gamma_f * h_q;
    
    return { q, h_q };
  }

  /**
   * 浅埋溶洞土压力计算
   * 适用于溶洞埋深较浅时的土压力计算，考虑了洞顶土体滑动影响
   * 
   * @param gamma_f 溶洞充填物重度(kN/m³)
   * @param h_f 溶洞拱部溶洞充填物厚度(m)，从地表到溶洞顶部的垂直距离
   * @param B_f 溶洞宽度(m)
   * @param lambda 充填物侧压力系数，反映水平方向土压力与垂直方向土压力的比例关系
   * @param theta 充填物竖向滑面摩擦角(°)，土体滑动面与垂直方向的夹角
   * @returns {number} q_shallow - 浅埋条件下溶洞顶部的土压力值(kPa)
   */
  static caveSoilPressureShallow(gamma_f: number, h_f: number, B_f: number, lambda_: number, theta: number): { q_shallow: number } {
    // 将角度从度数转换为弧度，用于数学计算
    const theta_rad = theta * Math.PI / 180;
    
    // 浅埋溶洞土压力计算公式：
    // q_shallow = γ_f × h_f × [1 - (h_f / B_f) × λ × tan(θ)]
    // 其中 [1 - (h_f / B_f) × λ × tan(θ)] 为浅埋修正系数
    const q_shallow = gamma_f * h_f * (1 - (h_f / B_f) * lambda_ * Math.tan(theta_rad));
    
    return { q_shallow };
  }

  /**
   * 计算λ值 - 深埋无限土体算法
   * 计算深埋条件下无限土体的侧压力系数，基于朗肯土压力理论
   * 适用于埋深较大、土体积无限延伸的情况
   * 
   * @param varphi_c 计算内摩擦角(°)，反映土体的抗剪强度特性
   * @returns {number} lambda_value - 朗肯主动土压力系数
   * @remarks 公式来源于朗肯土压力理论：λ = tan²(45° - φ_c/2)
   */
  static deepInfinite(varphi_c: number): { lambda_value: number } {
    // 将角度从度数转换为弧度，用于数学计算
    const varphi_c_rad = varphi_c * Math.PI / 180;
    
    // 计算朗肯主动土压力系数：λ = tan²(45° - φ_c/2)
    // 其中45°对应π/4弧度，φ_c/2需要转换为弧度进行计算
    const lambda_value = Math.pow(Math.tan(Math.PI/4 - varphi_c_rad/2), 2);
    
    return { lambda_value };
  }

  /**
   * 计算λ值 - qws算法
   * 溶洞侧墙垂直应力系数计算，适用于分析溶洞侧墙垂直方向的应力分布
   * 基于弹塑性理论，考虑土体的内摩擦特性
   * 
   * @param alpha 充填物表面与水平面夹角(°)，反映溶洞表面的倾斜程度
   * @param varphi_c 计算内摩擦角(°)，土体抵抗剪切破坏的能力指标
   * @returns {number} lambda_value - 侧墙垂直应力系数
   * @throws {Error} 当参数不满足计算条件时抛出错误
   */
  static qws(alpha: number, varphi_c: number): { lambda_value: number } {
    // 将角度从度数转换为弧度，用于数学计算
    const alpha_rad = alpha * Math.PI / 180;
    const varphi_c_rad = varphi_c * Math.PI / 180;

    // 计算三角函数值
    const cos_alpha = Math.cos(alpha_rad);
    const cos_varphi_c = Math.cos(varphi_c_rad);
    
    // 参数有效性检查，确保开平方运算有意义
    const termUnderSqrt = Math.pow(cos_alpha, 2) - Math.pow(cos_varphi_c, 2);
    if (termUnderSqrt < 0) {
      throw new Error('计算参数不满足条件: cos(alpha)^2 必须大于等于 cos(varphi_c)^2');
    }
    
    // 计算平方根项
    const sqrt_term = Math.sqrt(termUnderSqrt);
    
    // 计算分子和分母
    const numerator = cos_alpha - sqrt_term; // 分子
    const denominator = cos_alpha + sqrt_term; // 分母

    // 避免除以零的情况
    if (denominator === 0) {
      throw new Error('计算过程中出现除以零的情况');
    }

    // 计算lambda值：λ = (cos(alpha) - sqrt(cos²(alpha) - cos²(varphi_c))) / (cos(alpha) + sqrt(cos²(alpha) - cos²(varphi_c)))
    const lambda_value = numerator / denominator;
    return { lambda_value };
  }

  /**
   * 计算λ值 - qwx算法
   * 溶洞侧墙水平应力系数计算，适用于分析溶洞侧墙水平方向的应力分布
   * 考虑了土体的内摩擦特性和溶洞表面倾斜角度的影响
   * 
   * @param phi 内摩擦角(°)，反映土体或岩体的摩擦特性
   * @param varphi_c 计算内摩擦角(°)，用于理论计算的修正内摩擦角
   * @param alpha 充填物表面与水平面夹角(°)，反映溶洞表面的倾斜程度
   * @returns {number} lambda_value - 侧墙水平应力系数
   */
  static qwx(phi: number, varphi_c: number, alpha: number): { lambda_value: number } {
    // 将角度从度数转换为弧度，用于数学计算
    const phi_rad = phi * Math.PI / 180;
    const varphi_c_rad = varphi_c * Math.PI / 180;
    const alpha_rad = alpha * Math.PI / 180;

    // 计算各角度的正切值
    const tan_phi = Math.tan(phi_rad);
    const tan_varphi_c = Math.tan(varphi_c_rad);
    const tan_alpha = Math.tan(alpha_rad);

    // 计算tan(theta)，其中theta为破裂面与垂直方向的夹角
    const numerator_theta = -tan_phi + Math.sqrt((1 + Math.pow(tan_varphi_c, 2)) * (1 + tan_alpha / tan_varphi_c));
    const denominator_theta = 1 + (1 + Math.pow(tan_varphi_c, 2)) * tan_alpha / tan_varphi_c;
    const tan_theta = numerator_theta / denominator_theta;

    // 计算实际的theta角度（弧度）
    const theta = Math.atan(tan_theta);
    
    // 计算lambda值：λ = tan(theta) / [tan(theta + φ) × (1 + tan(alpha) × tan(theta))]
    const lambda_value = tan_theta / (Math.tan(theta + phi_rad) * (1 + tan_alpha * tan_theta));
    return { lambda_value };
  }

  /**
   * 计算λ值 - qys算法
   * 溶洞底板垂直应力系数计算，适用于分析溶洞底板垂直方向的应力分布
   * 考虑了溶洞几何形状、摩擦特性和土压力方向的影响
   * 
   * @param m 填充物表面坡率，反映填充物表面的倾斜程度
   * @param n 溶洞壁隧道填充物表面交叉点连线坡率，反映溶洞壁形状特征
   * @param mu 溶腔壁充填物之间摩擦系数，反映接触面的摩擦特性
   * @param delta 侧向土压力与水平线夹角(°)，反映土压力的作用方向
   * @returns {number} lambda_value - 底板垂直应力系数
   */
  static qys(m: number, n: number, mu: number, delta: number):  { lambda_value: number } {
    // 将角度从度数转换为弧度，用于数学计算
    const delta_rad = delta * Math.PI / 180;

    // 计算几何形状修正系数 term1 = (m × n) / (m - n)
    const numerator_mn = m * n;
    const denominator_mn = m - n;
    const term1 = numerator_mn / denominator_mn;

    // 计算摩擦和方向修正系数 term2 = (1 - μ × n) / [(μ + n) × cos(δ) + (1 - μ × n) × sin(δ)]
    const numerator = 1 - mu * n;
    const denominator = (mu + n) * Math.cos(delta_rad) + (1 - mu * n) * Math.sin(delta_rad);
    const term2 = numerator / denominator;

    // 计算最终的lambda值：λ = term1 × term2
    const lambda_value = term1 * term2;
    return { lambda_value };
  }

  /**
   * 计算λ值 - qyx算法
   * 溶洞底板水平应力系数计算，适用于分析溶洞底板水平方向的应力分布
   * 与qys算法类似，但针对水平方向的应力计算进行了调整
   * 
   * @param m 填充物表面坡率，反映填充物表面的倾斜程度
   * @param n 溶洞壁隧道填充物表面交叉点连线坡率，反映溶洞壁形状特征
   * @param mu 溶腔壁充填物之间摩擦系数，反映接触面的摩擦特性
   * @param delta 侧向土压力与水平线夹角(°)，反映土压力的作用方向
   * @returns {number} lambda_value - 底板水平应力系数
   */
  static qyx(m: number, n: number, mu: number, delta: number):  { lambda_value: number } {
    // 将角度从度数转换为弧度，用于数学计算
    const delta_rad = delta * Math.PI / 180;

    // 计算几何形状修正系数 term1 = (m × n) / (m + n)
    // 注意：与qys算法不同，这里使用的是(m + n)作为分母
    const numerator_mn = m * n;
    const denominator_mn = m + n;
    const term1 = numerator_mn / denominator_mn;

    // 计算摩擦和方向修正系数 term2 = (1 - μ × n) / [(μ + n) × cos(δ) + (1 - μ × n) × sin(δ)]
    // 与qys算法相同的摩擦和方向修正项
    const numerator = 1 - mu * n;
    const denominator = (mu + n) * Math.cos(delta_rad) + (1 - mu * n) * Math.sin(delta_rad);
    const term2 = numerator / denominator;

    // 计算最终的lambda值：λ = term1 × term2
    const lambda_value = term1 * term2;
    return { lambda_value };
  }


  /**
   * 侧向土压力计算
   * 计算溶洞侧墙所受的侧向土压力，包括不同位置的土压力值
   * 适用于分析溶洞侧墙的受力状态
   * 
   * @param gamma_f 土体重度(kN/m³)
   * @param h_f 上覆土厚度(m)，从地表到计算点的垂直距离
   * @param h1 附加计算高度(m)，用于计算平均土压力
   * @param lambda_1 侧压力系数，反映水平方向土压力与垂直方向土压力的比例关系
   * @returns {e1: number, e1_prime: number} 侧向土压力计算结果
   * @returns {number} e1 - 左侧拱部侧向土压力值(kPa)
   * @returns {number} e1_prime - 平均侧向土压力值(kPa)
   */
  static lateralSoilPressure(gamma_f: number, h_f: number, h1: number, lambda_1: number): { e1: number, e1_prime: number } {
    // 计算左侧拱部侧向土压力: e₁ = γ_f * h_f * λ₁
    // 这是基于库仑土压力理论的侧向土压力计算
    const e1 = gamma_f * h_f * lambda_1;
    
    // 计算平均侧向土压力: e₁' = 0.5 * γ_f * (h_f + h1) * λ₁
    // 用于计算土压力的平均值，考虑了高度变化的影响
    const e1_prime = 0.5 * gamma_f * (h_f + h1) * lambda_1;
    
    return { e1, e1_prime };
  }


  /**
   * 落石冲击荷载强度计算
   * 计算落石冲击作用在结构上的压力强度
   * 考虑了落石尺寸、缓冲层效果和冲击扩散的影响
   * 
   * @param Fr 冲击荷载(kN)，落石与结构撞击时产生的总冲击力
   * @param Dr 落石直径(m)，落石的等效直径
   * @param Tb 缓冲层厚度(m)，结构表面的缓冲材料厚度
   * @param beta 冲击荷载扩散角(°)，荷载在缓冲层中扩散的角度
   * @param phi_b 岩土内摩擦角(°)，反映岩土材料的抗剪特性
   * @returns {number} 冲击荷载强度(kPa)，单位面积上的冲击力
   */
  static rockImpactStrength(Fr: number, Dr: number, Tb: number, beta: number, phi_b: number): { rock_impact_strength: number } {
    // 将角度从度数转换为弧度，用于数学计算
    const beta_rad = beta * Math.PI / 180;
    
    // 计算荷载扩散后的等效半径: r = D_r/2 + T_b·tanβ
    // 其中 D_r/2 是落石半径，T_b·tanβ 是由于缓冲层扩散增加的半径
    const radius_term = Dr / 2 + Tb * Math.tan(beta_rad);
    
    // 计算冲击荷载强度: p_r = F_r / πr²
    // 压力强度等于总荷载除以作用面积（圆形面积）
    return { rock_impact_strength: Fr / (Math.PI * Math.pow(radius_term, 2)) };
  }

  /**
   * 落石冲击荷载组合计算
   * 综合计算落石冲击的关键参数，包括速度、冲击时间和冲击荷载
   * 基于能量守恒和动量定理，考虑了落石特性和缓冲层影响
   * 
   * @param mr 落石质量(kg)，落石的总质量
   * @param Hr 下落高度(m)，落石从释放点到冲击点的垂直距离
   * @param Tb 缓冲层厚度(m)，结构表面的缓冲材料厚度
   * @param g 重力加速度(m/s²)，默认值为9.8m/s²
   * @returns {v0: number, t: number, Fr: number} 落石冲击参数计算结果
   * @returns {number} v0 - 落石冲击速度(m/s)，冲击瞬间的瞬时速度
   * @returns {number} t - 冲击时间(s)，冲击过程持续的时间
   * @returns {number} Fr - 冲击荷载(kN)，落石与结构撞击时产生的总冲击力
   */
  static calculateRockImpactLoadCombined(mr: number, Hr: number, Tb: number, g: number = 9.8): { v0: number, t: number, Fr: number } {
    // 计算落石冲击速度: v0 = √(2g·Hr)
    // 基于自由落体运动的速度计算公式，忽略空气阻力
    const v0 = Math.sqrt(2 * g * Hr);
    
    // 计算冲击时间: t = (0.097mr·g + 2.21Tb + 0.045/Hr + 1.2)/100
    // 经验公式，综合考虑了落石质量、缓冲层厚度和下落高度的影响
    const t = (0.097 * mr * g + 2.21 * Tb + 0.045 / Hr + 1.2) / 100;
    
    // 计算冲击荷载: Fr = (mr·v0)/(1000t)
    // 基于动量定理：冲量(F·t)等于动量变化(m·v)，单位转换为kN
    const Fr = (mr * v0) / (1000 * t);
    
    return { v0, t, Fr };
  }
}